﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.ServiceLocation;
using StyleMVVM.DependencyInjection;

namespace StyleMVVM.DotNet.ServiceLocator
{
	/// <summary>
	/// Default implementation of IServiceLocator
	/// </summary>
	public class StyleMVVMServiceLocator : IServiceLocator
	{
		private IDependencyInjectionContainer container;

		public StyleMVVMServiceLocator(IDependencyInjectionContainer container)
		{
			if (container == null)
			{
				throw new ArgumentNullException("container");
			}

			this.container = container;
		}

		/// <summary>
		/// Gets the service object of the specified type.
		/// </summary>
		/// <returns>
		/// A service object of type <paramref name="serviceType"/>.-or- null if there is no service object of type <paramref name="serviceType"/>.
		/// </returns>
		/// <param name="serviceType">An object that specifies the type of service object to get. </param><filterpriority>2</filterpriority>
		public object GetService(Type serviceType)
		{
			try
			{
				return container.LocateByType(serviceType);
			}
			catch (Exception exp)
			{
				throw new ActivationException(exp.Message, exp);
			}
		}

		/// <summary>
		/// Get an instance of the given <paramref name="serviceType"/>.
		/// </summary>
		/// <param name="serviceType">Type of object requested.</param><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is an error resolving
		///             the service instance.</exception>
		/// <returns>
		/// The requested service instance.
		/// </returns>
		public object GetInstance(Type serviceType)
		{
			try
			{
				return container.LocateByType(serviceType);
			}
			catch (Exception exp)
			{
				throw new ActivationException(exp.Message, exp);
			}
		}

		/// <summary>
		/// Get an instance of the given named <paramref name="serviceType"/>.
		/// </summary>
		/// <param name="serviceType">Type of object requested.</param><param name="key">Name the object was registered with.</param><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is an error resolving
		///             the service instance.</exception>
		/// <returns>
		/// The requested service instance.
		/// </returns>
		public object GetInstance(Type serviceType, string key)
		{
			if (key == null)
			{
				try
				{
					return container.LocateByType(serviceType);
				}
				catch (Exception exp)
				{
					throw new ActivationException(exp.Message, exp);
				}
			}

			throw new NotSupportedException("Locating by type and key is not supported");
		}

		/// <summary>
		/// Get all instances of the given <paramref name="serviceType"/> currently
		///             registered in the container.
		/// </summary>
		/// <param name="serviceType">Type of object requested.</param><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is are errors resolving
		///             the service instance.</exception>
		/// <returns>
		/// A sequence of instances of the requested <paramref name="serviceType"/>.
		/// </returns>
		public IEnumerable<object> GetAllInstances(Type serviceType)
		{
			try
			{
				return container.LocateAllByType(serviceType);
			}
			catch (Exception exp)
			{
				throw new ActivationException(exp.Message, exp);
			}
		}

		/// <summary>
		/// Get an instance of the given <typeparamref name="TService"/>.
		/// </summary>
		/// <typeparam name="TService">Type of object requested.</typeparam><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is are errors resolving
		///             the service instance.</exception>
		/// <returns>
		/// The requested service instance.
		/// </returns>
		public TService GetInstance<TService>()
		{
			try
			{
				return (TService)container.LocateByType(typeof(TService));
			}
			catch (Exception exp)
			{
				throw new ActivationException(exp.Message, exp);
			}
		}

		/// <summary>
		/// Get an instance of the given named <typeparamref name="TService"/>.
		/// </summary>
		/// <typeparam name="TService">Type of object requested.</typeparam><param name="key">Name the object was registered with.</param><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is are errors resolving
		///             the service instance.</exception>
		/// <returns>
		/// The requested service instance.
		/// </returns>
		public TService GetInstance<TService>(string key)
		{
			if (key == null)
			{
				try
				{
					return (TService)container.LocateByType(typeof(TService));
				}
				catch (Exception exp)
				{
					throw new ActivationException(exp.Message, exp);
				}
			}

			throw new NotSupportedException("Locating by type and key is not supported");
		}

		/// <summary>
		/// Get all instances of the given <typeparamref name="TService"/> currently
		///             registered in the container.
		/// </summary>
		/// <typeparam name="TService">Type of object requested.</typeparam><exception cref="T:Microsoft.Practices.ServiceLocation.ActivationException">if there is are errors resolving
		///             the service instance.</exception>
		/// <returns>
		/// A sequence of instances of the requested <typeparamref name="TService"/>.
		/// </returns>
		public IEnumerable<TService> GetAllInstances<TService>()
		{
			try
			{
				return container.LocateAll<TService>();
			}
			catch (Exception exp)
			{
				throw new ActivationException(exp.Message, exp);
			}
		}
	}
}
